package cn.elwy.rcp.kit.builder.decode;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import cn.elwy.common.util.io.FileUtil;
import cn.elwy.rcp.ui.util.ImageUtil;

public class FileChooser extends Composite {

	private Tree filesTree = null;
	private TreeViewer treeViewer = null;
	private List<File> files;

	public List<File> getFiles() {
		return files;
	}

	private static Image FS_ROOT = null;
	private static Image FS_FOLDER = null;
	// private static Image FS_FILE = null;
	private boolean isMulti = false;

	public FileChooser(Composite parent, String pathToOpen, boolean isDir, String[] allowedFileExtensions,
			boolean isMulti) {
		super(parent, SWT.NULL);
		this.isMulti = isMulti;
		initialize();

		treeViewer.setContentProvider(new ITreeContentProvider() {

			@Override
			public Object[] getChildren(Object parentElement) {
				return ((File) parentElement).listFiles();
			}

			@Override
			public Object getParent(Object element) {
				return ((File) element).getParentFile();
			}

			@Override
			public boolean hasChildren(Object element) {
				return ((File) element).isDirectory();
			}

			@Override
			public Object[] getElements(Object inputElement) {
				return (Object[]) inputElement;
			}

			@Override
			public void dispose() {

			}

			@Override
			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

			}

		});

		treeViewer.setLabelProvider(new LabelProvider() {
			@Override
			public String getText(Object element) {
				File f = (File) element;
				if (f.getParent() == null) {
					return f.getAbsolutePath();
				} else {
					return f.getName();
				}
			}

			@Override
			public Image getImage(Object element) {
				File file = (File) element;
				return ImageUtil.getProgramImage(file);
				// if (file.getParent() == null) {
				// return FS_ROOT;
				// } else if (file.isDirectory()) {
				// return FS_FOLDER;
				// } else {
				// String extName = FileUtil.getExtName(file.getName());
				// return loadProgramImage(extName);
				// }
			}
		});

		if (isDir)
			treeViewer.addFilter(new AllowOnlyFoldersFilter());

		treeViewer.addFilter(new FileExtFilter(allowedFileExtensions));

		treeViewer.setComparator(new FileSorter());
		treeViewer.setInput(File.listRoots());
		File selPath = new File(pathToOpen);
		treeViewer.expandToLevel(selPath, 1);
		treeViewer.setSelection(new StructuredSelection(selPath), true);

		this.addDisposeListener(new DisposeListener() {
			@Override
			public void widgetDisposed(DisposeEvent e) {
				initFiles();
			}
		});
	}

	private void initFiles() {
		files = new ArrayList<File>();
		for (TreeItem treeItem : filesTree.getSelection()) {
			files.add((File) treeItem.getData());
		}
	}

	private void initialize() {
		GridData gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridData.verticalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridData.grabExcessVerticalSpace = true;
		filesTree = new Tree(this, SWT.BORDER | (isMulti ? SWT.MULTI : SWT.SINGLE));
		filesTree.setLinesVisible(true);
		filesTree.setLayoutData(gridData);
		treeViewer = new TreeViewer(filesTree);
		setSize(new Point(500, 600));
		setLayout(new GridLayout());

		if (FS_ROOT == null)
			FS_ROOT = ImageUtil.getImage(ImageUtil.class, "/icons/harddisk_16.png");
		if (FS_FOLDER == null)
			FS_FOLDER = ImageUtil.getImage(ImageUtil.class, "/icons/folder_16.png");
		// if (FS_FILE == null)
		// FS_FILE = loadProgramImage(".doc");
	}

	class FileSorter extends ViewerComparator {
		@Override
		public int category(Object element) {
			return ((File) element).isDirectory() ? 0 : 1;
		}
	}

	class AllowOnlyFoldersFilter extends ViewerFilter {
		@Override
		public boolean select(Viewer viewer, Object parent, Object element) {
			if (parent == treeViewer.getInput())
				return true;
			return ((!((File) element).isHidden()));
		}
	}

	class FileExtFilter extends ViewerFilter {

		private String[] allowedFileExtensions;

		/**
		 * Creates new instance of filter.
		 * @param allowedFileExtensions list of file extension the filter has to recognize or <code>null</code> if all files
		 *          are allowed
		 */
		public FileExtFilter(String[] allowedFileExtensions) {
			this.allowedFileExtensions = allowedFileExtensions;
		}

		@Override
		public boolean select(Viewer viewer, Object parent, Object element) {
			if (element instanceof File) {
				{
					if (((File) element).isDirectory())
						return true;
					return hasAllowedFileExtension((File) element);
				}
			}

			return true;
		}

		private boolean hasAllowedFileExtension(File file) {
			if (allowedFileExtensions == null) {
				return true;
			}
			return checkExtFile(allowedFileExtensions, file.getName());
		}

		private boolean checkExtFile(String[] exts, String fileName) {

			String file = fileName.toLowerCase();
			for (String element : exts)
				if (file.endsWith("." + element))
					return true;
			return false;
		}
	}

}
